

;	=======================================================
;
;	REC module containing RAM storage, I/O programs, main
;	program, and the directory. The complete set of modules
;	comprises REC.MAC, PDL.MAC, MARKOV.MAC, RECLIB.MAC, and
;	FXT.MAC.  RECLIB.MAC may be omitted if the operator X
;	isn't used, and must be substituted by another module
;	if the collection of subroutines to be called by X is
;	to be changed.
;
;	FXT.MAC contains the following REC operators and
;	predicates:
;
;		C	compile a REC expression
;		i	input from designated port
;		k	call CP/M without residue
;		K	call CP/M, preserve FCB, return value
;		o	output from designated port
;		R	read one character from console
;		t	type message given header
;		T	type argument on PDL
;		W	write argument on LST:
;		x	execute REC subroutine
;		`	test if a character waits at keyboard
;
;	REC version released during the 1980  Summer School of
;	the Microcomputer Applications Group of the I.C.U.A.P.
;
;		     FXT86  -  Copyright (C) 1982
;		    Universidad Autonoma de Puebla
;	      49 Poniente 1102 -  Puebla, Puebla, Mexico
;			 All Rights Reserved
;
;		 [Harold V. McIntosh,  28 August 1980]
;
;	Modification 1 - 1 January 1981.
;		a) Main program derives the values of const,
;		   conin, conou from the address rst0 supposing
;		   that BIOS starts out with the standard jump
;		   vector.  Thus, REC need not be reassembled
;		   to have fast access to I/O when CP/M varies.
;		b) T protected by pushes and pops of dx and bx.
;		c) Some changes made in memory allocation.
;	24 May 1981 - Zero flag to restrain L from too many pops
;	25 March 1982 - Y is now a predicate
;	29 May 1983 - ~ discontinued as argument exchange
;	29 May 1983 - ~ for unary negative or complement
;	29 May 1983 - N for numerical comparison on PDL
;	29 May 1983 - h discontinued, replaced by ''w
;	30 May 1983 - CPIR: jumps to BOOT rather than RER
;	8 July 1983 - C has object program origin as argument
;	8 July 1983 - C is an operator
;	8 July 1983 - C0 defined as lower bound of compile area
;	8 July 1983 - x moved from RECLIB
;	8 July 1983 - x is a predicate to call REC subroutines
;	9 July 1983 - Buffered CP/M input if no disk file given
;	14 July 1983 - W had its arguments reversed
;	14 January 1984 - <QIN ds 0>, <QOU ds 0> for sorcim.cnv
;	14 January 1984 - default extension .REC for 1st file
;	=======================================================

;	Absolute program locations used by CP/M.

bdos	equ	224		;CP/M-86 software interrupt vector

TFCB	equ	.005CH		;CP/M file control block
TALT	equ	.006CH		;CP/M alternate file name
FSIZ	equ	0010H		;CP/M file name size
HSIZ	equ	FSIZ/2
TBUF	equ	.0080H		;CP/M disk buffer location
TSIZ	equ	0080H		;CP/M disk buffer size

;	-----------------------------------------------------
;	RAM memory which is required for the operation of REC
;	-----------------------------------------------------

;	Relay area for input and output subroutines.

read	dw	chin		;character input for REC compiler
tyin	dw	chin		;single character input for R
tyou	dw	chou		;single character output for T

;	Temporary storage used by the REC compiler.

XPD	dw	0000		;colon jump back to left parenthesis
YPD	dw	0000		;false predicate jump chain
ZPD	dw	0000		;semicolon exit chain

;	Pointers to the directories.

FXT	dw	FT		;pointer to fixed operator directory
VRT	dw	VT		;pointer to subroutine directory

;	Pointers to the area of compiled subroutines.

C0	dw	KA		;lower limit of compile area
C1	dw	KA		;beginning of present compilation
C2	dw	EK		;upper limit of compile area

;	Pointers to REC/MARKOV pushdown list.

PX	dw	PD+2		;beginning of pushdown text
PY	dw	PD+2		;end of pushdown text
PZ	dw	EP		;end of available pushdown space

;	Workspace pointers.

P0	dw	WS		;beginning of workspace
P1	dw	WS		;beginning of marked segment
P2	dw	WS		;end of marked segment
P3	dw	WS		;end of text
P4	dw	EW		;end of workspace

;	I-O pointers.

RX	dw	0000
RY	dw	0000

;	Linkage to input-output through ports.

QIN	rw	0		;space holder
	DB	0ECH		;8-bit 8086 static IN instruction
QI	db	00H
	ret

QOU	rw	0		;space holder
	DB	0E6H		;8-bit 8086 static OUT instruction
QO	db	00H
	ret

;	Error flag.

ER	dw	0000

;	=======================================================
;	Programs related to input-output and disk usage.
;	=======================================================

;	bootstrap routine

boot:	mov	cl,(offset ze)
	mov	dl,(offset ze)
	int	bdos

;	Buffer read routine.

PTY:	push	bx		;conserve (bx)
	mov	bx,RX		;pointer to read buffer
	mov	al,[bx]		;fetch byte
	inc	bx		;advance pointer to next byte
	mov	RX,bx		;update buffer pointer
	pop	bx		;restore (bx) - preserve all reg pairs
	ret

;	Console character read routine.  Strict CP/M compatible
;	version, which has characteristics undesirable for some
;	applications, such as an automatic echo or preemption
;	of some of the control characters for editing purposes.
;	When it is used, programs must forego their own echo,
;	and do their own editing when required.  This version has
;	direct access to CONIN.

chin:	push	cx
	push	dx
chi:	mov	dl,-1
	mov	cl,6
	int	bdos
	or	al,al
	jz	chi
	pop	dx
	pop	cx
	ret

;	Buffered console character read routine, which is more
;	practical for use with CP/M.  Up to 126 characters may be
;	read using CP/M function 10, which is sufficient for
;	bootstrapping or generating test programs. CHIN should be
;	used for longer input sequences, which must be error-free
;	- incoming through a modem for example.

buin:	push	bx
	push	cx
	push	dx
	mov	bx,RX
	cmp	bx,RY
	jnz	BI5
	mov	cl,9		;(09) write message
	mov	dx,(offset bume)
	int	bdos
	mov	cl,10		;(0A) buffered read
	mov	dx,(offset TBUF)
	int	bdos
	mov	cl,9		;(09) write message
	mov	dx,(offset crlf)
	int	bdos
	mov	bx,(offset TBUF)+2
	mov	RX,bx
	mov	al,-1[bx]
	mov	ah,0
	add	ax,bx
	mov	RY,ax
BI5:	mov	al,[bx]
	inc	bx
	mov	RX,bx
	pop	dx
	pop	cx
	pop	bx
	ret

logo	db	0DH,0AH,'        REC(8086)/ICUAP',0DH,0AH
	db	'Universidad Autonoma de Puebla',0DH,0AH
	db	'        January 23, 1984',0DH,0AH,'$'
bume	db	0DH,0AH,'REC86> $'
crlf	db	0DH,0AH,'$'

bure:	mov	al,TSIZ-2
	mov	TBUF,al
	mov	ax,(offset buin)
	mov	read,ax
	mov	ax,(offset TBUF)
	mov	RX,ax
	mov	RY,ax
	ret

;	Console character out routine.  Strict CP/M compatible
;	version, which unfortunately makes so many tests and
;	jumps that it is unsuitable for programs such as the
;	cursor editor which frequently write a full screen.
;	This is a version with direct access to CONOUT.

chou:	push	cx
	push	dx
	mov	dl,al
	mov	cl,6		;direct console I-O
	int	bdos
	pop	dx
	pop	cx
	ret

;	(`)  Test for presence of waiting character (FALSE if
;	none waiting).  This is a version with fast access to 
;	CONST, which is required when the fast CHIN is used,
;	because CP/M has some internal buffers which will 
;	otherwise distort the results.

chaw:	push	cx
	push	dx
	mov	dl,-2
	mov	cl,6		;direct console I-O
	int	bdos
	pop	dx
	pop	cx
	ror	al,1
	jb	chw
	ret
chw:	jmp	SKP

;	Printer output routine.

PROU:	push	bx
	push	dx
	push	cx
	mov	cl,5		;output through LST:
	mov	dl,al
	int	bdos
	pop	cx
	pop	dx
	pop	bx
	ret

;	(R)  REC read operator.

UCR:	mov	cx,1		;one byte to be inserted
	call	NARG		;close last arg, verify space
	push	bx
	mov	bx,tyin
	call	bx		;get byte from console input
	pop	bx
	mov	[bx],al		;store on PDL
	inc	bx		;advance pointer
	mov	PY,bx		;save as terminator
	ret

;	(t) Write indirect operator.  <org,siz,t> prints the
;	indicated message, leaves no residue.

LCT:	mov	bx,PX		;fetch argument pointer
	call	TWOL		;move two args to 8080 stack
	pop	dx		;second arg (org) into (dx)
	pop	bx		;top arg (siz) into (bx)
	add	bx,dx		;org+siz=end
	xchg	bx,dx		;(dx)=end, (bx)=org
	jmp	UT1		;use write cycle in UCT

;	(T)  REC write operator.  <'XXX' T> will write XXX on
;	the console, leaving it on the PDL.

uct:	mov	dx,py		;fetch terminal address
	mov	bx,px		;beginning address to (bx)
ut1:	cmp	dx,bx		;
	jz	ut2		;they match, we're done
	mov	al,[bx]		;get byte out of memory
	push	bx		;the registers dx and bx
	push	dx		;are essential for the loop
	mov	bx,tyou
	call	bx
	pop	dx		;recover the saved registers
	pop	bx		;
	inc	bx		;advance pointer
	jmp	UT1		;repeat
ut2:	ret

;	(W)  REC print operator.  <org, siz, W> will print the
;	indicated text on the list device, and then erase its
;	arguments.

UCW:	mov	bx,PX		;pointer to arguments
	call	TWOL		;2 args from PDL to 8080 stack
	pop	bx		;place text origin in (bx)
	pop	dx		;place length in (dx)
UWW:	cmp	dx,dx		;check for zero length
	jz	UWX		;no more to print
	mov	al,[bx]		;fetch a byte
	push	bx		;we need to be sure that dx and bx are
	push	dx		;preserved whatever the print routine
	call	PROU		;send it to printer
	pop	dx		;recover bx
	pop	bx		;and dx
	dec	dx		;diminish count
	inc	bx		;advance pointer
	jmp	UWW		;repeat
UWX:	ret

;	(i)  Input from designated port.  <port, i> leaves
;	<port, byte> so that after disposing of <byte>, <port>
;	can be reused.

LCI:	mov	bx,PX		;get pointer to top argument on PDL
	mov	al,[bx]		;only the low order byte matters
	mov	QI,al		;place it in teme IN instruction
	mov	cx,1		;we're only going to read one byte
	call	NARG		;prepare a place for it on the PDL
	call	QIN		;execute the captive IN instruction
	mov	[bx],al		;storing the incoming byte on the PDL
	inc	bx		;always ready for the next byte
	mov	PY,bx		;close off the argument
	ret			;and we're through

;	(o) Output from designated port  -  <port, byte, o>
;	leaves <port>, facilitating multiple OUTs through the
;	same port.

LCO:	mov	bx,PX		;pointer to last argument - output byte
	mov	CH,[bx]		;tuck it into register b
	call	UCL		;erase the top argument
	mov	al,[bx]		;(bx) points to next argument - get it
	mov	QO,al		;store in tame OUT instruction
	mov	al,CH		;output must be from accumulator
	jmp	QOU		;execute the prepared OUT instruction

;	=======================================================
;
;	Communication with CP/M takes two forms:  <FCB, n, K>
;	which leaves <FCB, code> on the pushdown list, or else
;	<FCB, n, k> which leaves nothing on the pushdown list.
;	In either case - FCB is a two-byte parameter, usually
;	the address of the file control block - but it could
;	also be a DMA address or sometimes even null for the
;	sake of uniformity.  Approximately thirty options are
;	available which are numbered serially, indicated by the
;	argument n.  The difference between K and k is that the
;	former conserves the parameter FCB for possible use by
;	a subsequent CP/M call, and reports a result in the
;	one-byte result <code>.  This could be the character
;	read by an input routine or an error code for the disk
;	routines.
;
;	The options are:
;
;	num	function		"FCB"	"code"
;	---	--------		-----	------
;
;	 0	system reset		-	-
;	 1	read console		-	char
;	 2	write console		char	-
;	 3	read reader		-	char
;	 4	write punch		char	-
;	 5	write list		char	-
;	 6	-			-	-
;	 7	read i/o stat		-	stat
;	 8	write i/ stat		stat	-
;	 9	print buffer		buffer	-
;	10	read buffer		buffer	-
;	11	console status	-	stat
;
;	12	lift disk head		-	-
;	13	init disk only		-	-
;	14	select disk		disk	-
;	15	open file		fcb	code
;	16	close file		fcb	code
;	17	search once		fcb	code
;	18	search again		fcb	code
;	19	delete file		fcb	code
;	20	read 1 record		fcb	code
;	21	write 1 record		fcb	code
;	22	create file		fcb	code
;	23	rename file		fcb	code
;	24	read login		-	logv
;	25	read disklog		-	disk
;	26	set DMA address		dma	-
;	27	read bitmap		-	-
;
;	Fuller details of all the CP/M options and the way they
;	function can be obtained through consulting Digital
;	Research's manuals for CP/M, especially their "CP/M
;	Interface Guide."
;
;	=======================================================

;	(K)  Set up communication with CP/M - top into (bx),
;	next into (dx).  Preserve next, call BDOS, (Aze) into
;	top.

CPM:	mov	bx,PX		;fetch pointer to top argument
	mov	cx,[bx]		;load C from low byte
	mov	dx,-2[bx]	;load up (dx) with high byte
	xchg	bx,dx		;pointer into (bx)
	mov	dx,[bx]		;low byte of under argument
	int	bdos		;call BDOS with args in (bx), (dx)
	mov	bx,PX		;pointer to top argument again
	mov	[bx],al		;save low byte from A
	mov	byte ptr 1[bx],00	;make high byte a zero
	ret

;	(k)  Call to CP/M without any value returned.

CPML:	call	CXLD		;load top arg into (cx), lift it
	call	DXLD		;load next arg into (dx), lift it too
	int	bdos		;execute indicated operation
	ret

;	-------------------------------------------------------
;	Disk input-output routine working through CP/M.
;	-------------------------------------------------------

;	Set up a file control block with a given file name and
;	the default extension REC.  The pushdown list contains
;	the disk unit designation, then by the filename without
;	any extension. No protection is afforded against an
;	overly long file name, a nonexistent disk, or the like.
;	Some errors of this type must be caught by CP/M since
;	REC cannot know such things as the exact number of disk
;	drives that there will be.

DIIN:	cld
	mov	ax,ds
	mov	es,ax
	mov	cx,21H		;FCB requires 33 bytes
	mov	di,(offset TFCB)	;use CP/M's transient FCB
	mov	al,00H		;	;fill it with zeroes
	repnz	stos	byte [di]
	mov	cx,11		;filename field is 11 bytes long
	mov	di,(offset TFCB)+1	;field begins at second byte
	mov	al,' '		;fill it with blanks
	repnz	stos	byte [di]
	mov	bx,PX		;fetch pointer to top argument
	mov	al,[bx]		;load disk unit designator
	sub	al,'@'		;normalize to uppercase letters
	mov	TFCB,al		;store it in file control block
	call	UCL		;pop top argument
	mov	si,PX		;fetch pointer to file name
	mov	cx,PY		;end of file name
	sub	cx,si		;place py - px in (cx)
	mov	di,(offset TFCB)+1	;destination origin
	repnz	movs	byte [di],[si]
CPIN:	mov	cl,15		;<open file>
	mov	dx,(offset TFCB)	;file control block
	int	bdos		;
	cmp	al,0FFH	;check for error
	jz	CPIR
	mov	bx,(offset TBUF)	;origin of CP/M's sector buffer
	mov	RX,bx		;initial address of pseudotty
	mov	RY,bx		;provoke disk read
	ret
CPIR:	jmp	boot

;	Read from disk buffer, replenish buffer when empty.

DIRE:	push	bx		;save 3 8080 register pairs
	push	dx		;
	push	cx		;
	mov	bx,RX		;pointer to current byte
	cmp	bx,RY		;skip if equal
	jnz	DI5		;still have bytes in the buffer
	mov	cl,20		;<read next record>
	mov	dx,(offset TFCB)	;file control block
	int	bdos		;
	mov	bx,(offset TBUF)+TSIZ	;end of buffer
	mov	RY,bx		;store it in ry
	mov	bx,(offset TBUF)	;beginning of buffer
	mov	RX,bx		;store it in rx
DI5:	mov	al,[bx]		;common continuation
	inc	bx		;byte in acc, advance pointer
	mov	RX,bx		;store position of next byte
	pop	cx		;replace 3 register pairs
	pop	dx		;
	pop	bx		;
	ret

;	================
;	= main program =
;	================

;[change]
MAIN:	cli
	mov	ax,cs
	mov	ss,ax
	mov	sp,(offset STAK)
	sti
	mov	PD,(offset ZE)		;mark bottom of pushdown list
	mov	bx,(offset TFCB)
	cmp	byte ptr 1[bx],' '
	jz	tylo
	cmp	byte ptr 9[bx],' '
	jnz	yext
	mov	byte ptr 9[bx],'R'
	mov	byte ptr 10[bx],'E'
	mov	byte ptr 11[bx],'C'
yext:	mov	cx,HSIZ
;[endchange]
	mov	bx,(offset TALT)
pual:	push	word ptr [bx]		;save secondary file name
	inc	bx
	inc	bx
	loop	pual
	call	CPIN		;open disk file for REC program
	mov	bx,(offset DIRE)	;REC input through disk
	mov	read,bx		;REC compiler's I-O linkage
	call	INRE		;initialize REC compiler RAM
	call	EMCX		;compile the program file
	mov	cx,HSIZ
	mov	bx,(offset TFCB)+FSIZ
	pop	dx
poal:	dec	bx
	dec	bx
	pop	word ptr [bx]
	loop	poal
	push	dx
	call	EMCU		;execute the program file
	jmps	bootie		;return to CP/M if false
	nop			;beware jump span
bootie:	jmp	boot		;or even if it was true
tylo:	mov	cl,9		;(09) write message
	mov	dx,(offset logo)
	int	bdos
nodi:	call	bure
	call	INRE
	call	EMCX
	call	EMCU
	jmps	nodi
	nop
	jmp	nodi

;	(C) REC compiling operator which takes the designation
;	of the compiling source from the PDL. The alternatives
;	are:
;
;	      ''C		input program from console
;	    'file' 'D' C	take <file.rec> from disk D
;	       pC		pushdown list
;	       qC		workspace
;	    <org,siz,C>		memory from address org onward
;
;	In general, if the top argument is of length zero, the
;	console is the source, if it is of length one the named
;	disk is the source [@=current disk, A, B, ... up to the
;	system's limit], and if the argument has length 2, the
;	combination of <org, siz> from the memory applies.  It
;	is the programmer's responsibility to avoid nonexistent
;	memory, disk units, and the like.

UCC:	mov	ax,PY
	sub	ax,PX
	jz	UC2		;zero means console
	cmp	ax,1		;test for one byte
	jz	UC1		;one means disk designation
	cmp	ax,2		;verify that we've got two bytes
	jnz	UC7		;no provision for other than 1, 2 bytes
	mov	bx,(offset PTY)		;setup readin from pseudoteletype
	mov	read,bx		;
	call	CXLD		;load two numerical arguments
	mov	dx,[bx]		;bx contains PX for second argument
	mov	RX,dx		;origin of REC source code
	add	dx,cx		;length of source code
	mov	RY,dx		;end of source code
	jmp	UC4		;compile once rx, ry set up
UC1:	call	DIIN		;setup the CP/M FCB for given file
	mov	bx,(offset DIRE)	;setup input from disk reader
	jmp	UC3		;compile once input source set up
UC2:	mov	bx,(offset CHIN)	;input from the console
UC3:	mov	read,bx		;
UC4:	call	UCL
	mov	cx,PY
	sub	cx,PX
	cmp	cx,0
	jnz	UC5
	mov	dx,C1
	jmp	UC6
UC5:	cmp	cx,2
	jnz	UC7
	mov	bx,PX
	mov	dx,[bx]
	push	dx
	call	UCL
	pop	dx
	cmp	dx,C0
	jb	UC6
	cmp	C2,dx
	jb	UC6
	mov	C1,dx
UC6:	push	dx
	call	LEFT
	call	RECRR
	push	dx
	call	PUTW
	call	PUTW
	ret
UC7:	call	RER

;	(x)  Call a REC subroutine

go:	mov	bx,PX
	call	onel
	ret


;	======= here is the table of definitions of REC operators =====

FT	dw	NOOP		;blank
	dw	NOOP
	dw	RECOP		; [exclm]	binary to hex string
	dw	HX
	dw	RECDQ		; "	quoted expression
	dw	QU
	dw	RECOP		; #	binary to decimal string
	dw	NS
	dw	RECOP		; $	fetch a variable cell
	dw	VBLE
	dw	RECOP		; %	restrict to one byte
	dw	PE
	dw	RECOP		; &	exchange top numeric pair
	dw	EXCH
	dw	RECSQ		; '	quoted expression
	dw	QU
	dw	RECLP		; (
	dw	NOOP
	dw	RECRP		; )
	dw	NOOP
	dw	RECOP		; *	multiply
	dw	MPY
	dw	RECOP		; +	add
	dw	SUM
	dw	NOOP		; ,	separator like space
	dw	NOOP
	dw	RECMS		; -	subtract
	dw	DIF
	dw	RECOP		; .
	dw	NOOP
	dw	RECOP		; /	divide [remainder, quotient]
	dw	DVD
	dw	RECDD		; 0	number
	dw	NU
	dw	RECDD		; 1	number
	dw	NU
	dw	RECDD		; 2	number
	dw	NU
	dw	RECDD		; 3	number
	dw	NU
	dw	RECDD		; 4	number
	dw	NU
	dw	RECDD		; 5	number
	dw	NU
	dw	RECDD		; 6	number
	dw	NU
	dw	RECDD		; 7	number
	dw	NU
	dw	RECDD		; 8	number
	dw	NU
	dw	RECDD		; 9	number
	dw	NU
	dw	RECCO		; :
	dw	NOOP
	dw	RECSC		; ;
	dw	NOOP
	dw	RECOP		; <	restrict workspace
	dw	BRA
	dw	RECPR		; =	test equality of top pair
	dw	EQL
	dw	RECOP		; >	open workspace
	dw	KET
	dw	RECPR		; ?	test for error report
	dw	QM
	dw	RECP1		; @	execute subroutine
	dw	AR
	dw	RECPR		; A	advance pointer 1
	dw	UCA
	dw	RECPR		; B	retract pointer 1
	dw	UCB
	dw	RECOP		; C	compile
	dw	UCC
	dw	RECOP		; D	delete text
	dw	UCD
	dw	RECPR		; E	equality between WS and PD
	dw	UCE
	dw	RECPR		; F	find specified text
	dw	UCF
	dw	RECOP		; G	fetch a block from memory
	dw	GA
	dw	RECPR		; H	ASCII hex to binary
	dw	HE
	dw	RECOP		; I	insert
	dw	UCI
	dw	RECOP		; J	jump to front
	dw	UCJ
	dw	RECOP		; K	call CP/M, keep (dx), put value
	dw	CPM
	dw	RECOP		; L	erase top of PDL
	dw	UCL
	dw	RECPR		; M	compare PDL and workspace
	dw	UCM
	dw	RECPR		; N	numerical comparison
	dw	UCN
	dw	RECPR		; O	decimal ASCII string to binary
	dw	UCO
	dw	RECOP		; P	put block into buffered memory
	dw	UCP
	dw	RECOP		; Q	put workspace segment on PD
	dw	UCQ
	dw	RECOP		; R	read from keyboard
	dw	UCR
	dw	RECOP		; S	store block in memory
	dw	SA
	dw	RECOP		; T	write on screen
	dw	UCT
	dw	RECPR		; U	search, yielding interval
	dw	UCU
	dw	RECPR		; V	U, including endpoints
	dw	UCV
	dw	RECOP		; W	write on printer
	dw	UCW
	dw	RECOP		; X	call library subroutine
	dw	LIBR
	dw	RECPR		; Y	recover previous position of p1
	dw	UCY
	dw	RECOP		; Z	pointer 2 to end of text
	dw	UCZ
	dw	RECCM		; [	comment
	dw	NOOP
	dw	RECOP		; \	insert single byte in pair
	dw	IP
	dw	RECOP		; ]
	dw	NOOP
	dw	RECOP		; ^	increment top argument
	dw	INCR
	dw	RECOP		; _	exit to monitor
	dw	boot
	dw	RECPR		; `	true for waiting character
	dw	CHAW
	dw	RECPR		; a	segment forward from p1
	dw	LCA
	dw	RECPR		; b	segment backward from p2
	dw	LCB
	dw	RECOP		; c	create block on PDL
	dw	BLOK
	dw	RECPR		; d 	decrement but skip on zero
	dw	decR
	dw	RECPR		; e	extend workspace
	dw	LCE
	dw	RECPR		; f	block fill
	dw	LCF
	dw	RECOP		; g	non-incrementing byte fetch
	dw	GB
	dw	RECOP		; h
	dw	NOOP
	dw	RECOP		; i	input from designated port
	dw	LCI
	dw	RECOP		; j	null interval at p1
	dw	LCJ
	dw	RECOP		; k	call CP/M: no returned values
	dw	CPML
	dw	RECOP		; l	put pz on PDL
	dw	Lcl
	dw	RECOP		; m	set aside top argument
	dw	LCM
	dw	RECOP		; n	recover set-aside argument
	dw	LCN
	dw	RECOP		; o	output from designated port
	dw	LCO
	dw	RECOP		; p	put px, py-px on PDL
	dw	GXS
	dw	RECOP		; q	put p1, p2-p1 on PDL
	dw	LCQ
	dw	RECOP		; r	indirect replacement of address
	dw	IND
	dw	RECOP		; s	store block in memory wrt limit
	dw	LCS
	dw	RECOP		; t	type out indicated interval
	dw	LCT
	dw	RECOP		; u	incrementing byte fetch
	dw	GBI
	dw	RECOP		; v	incrementing byte store
	dw	SAI
	dw	RECOP		; w	store workspace header
	dw	LCW
	dw	RECPR		; x	subroutine jump  - no arguments
	dw	GO
	dw	RECOP		; y	fetch byte pair to PDL incr org
	dw	GWI
	dw	RECOP		; z	null interval at p2
	dw	LCZ
	dw	LBR		; {	start a definition string
	dw	NOOP
	dw	RECOP		; |	concatinate top two arguments
	dw	CONC
	dw	RECOP		; }	end a definition string
	dw	NOOP
	dw	RECOP		; ~	complement or negate top arg
	dw	COMP
	dw	RECOP		; del
	dw	NOOP

ENDREC	rw	0

;	Program locations and memory allocations.  Here is where
;	the memory is sectioned up into its functional components.

STAK	equ	.0FFEEH		;8086's pushdown stack

EW	equ	STAK-0800H	;end of the workspace
WS	equ	.0C000H		;beginning of the workspace

EK	equ	WS		;end of the compiling area
KA	equ	.06000H		;beginning of the compiling area

VT	equ	KA-0400H	;directory for programs compiled by REC

EP	equ	VT		;end of the pushdown list
PD	equ	ENDREC		;beginning of the pushdown list

	end


